package com.wenjie.databseDiff.handle.service.impl;


import cn.hutool.core.util.IdUtil;
import com.wenjie.databseDiff.entity.DatasourceConnectionAttr;
import com.wenjie.databseDiff.enums.DatasourceType;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.DatasourceConnectHelper;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.DatasourceSynchronizer;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.imp.H2DatasourceSynchronizer;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.imp.MysqlDatasourceSynchronizer;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.imp.OracleDatasourceSynchronizer;
import com.wenjie.databseDiff.handle.DatasourceSynchronizer.imp.PgsqlDatasourceSynchronizer;
import com.wenjie.databseDiff.handle.service.DatasourceSyncService;
import com.wenjie.original.entity.SysDiffColumn;
import com.wenjie.original.entity.SysDiffDatasource;
import com.wenjie.original.entity.SysDiffTable;
import com.wenjie.original.service.ISysDiffColumnService;
import com.wenjie.original.service.ISysDiffDatasourceService;
import com.wenjie.original.service.ISysDiffTableService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * @author wxg
 * <p>
 * Mysql数据源同步
 */
@Service
@Slf4j
public class DefaultDatasourceSyncServiceImpl implements DatasourceSyncService {
    @Autowired
    private ISysDiffDatasourceService sysDiffDatasourceService;
    @Autowired
    private ISysDiffTableService sysDiffTableService;
    @Autowired
    private ISysDiffColumnService sysDiffColumnService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sync(Long datasourceId) {
        SysDiffDatasource diffDatasource = sysDiffDatasourceService.getById(datasourceId);
        if (diffDatasource == null) {
            throw new RuntimeException("数据源不存在");
        }
        String database = diffDatasource.getDatabaseName();
        String type = diffDatasource.getType();
        String url = diffDatasource.getUrl();
        String username = diffDatasource.getUserName();
        String password = diffDatasource.getPassword();
        DatasourceType datasourceType = DatasourceType.of(type);
        DatasourceSynchronizer synchronizer = null;
        Long syncId = IdUtil.getSnowflakeNextId();

        log.info("Start sync diffDatasource,database:{}, type:{}, url:{} ,syncId:{}", database, type, url, syncId);
        setConnectionAttr(diffDatasource);
        try {
            switch (datasourceType) {
                case MYSQL:
                    synchronizer = new MysqlDatasourceSynchronizer(url, username, password);
                    break;
                case H2:
                    synchronizer = new H2DatasourceSynchronizer(url, username, password);
                    break;
                case PGSQL:
                    synchronizer = new PgsqlDatasourceSynchronizer(url, username, password);
                    break;
                case ORACLE:
                    synchronizer = new OracleDatasourceSynchronizer(url, username, password);
                    break;
                case TIDB:
                default:
                    throw new IllegalArgumentException("暂不支持: " + datasourceType);
            }
            List<SysDiffTable> tableInfos = synchronizer.getTables(database);
            for (SysDiffTable info : tableInfos) {
                info.setSysDiffDatasourceId(datasourceId);
                info.setSysDiffSyncId(syncId);
            }
            sysDiffTableService.saveBatch(tableInfos);

            int columnCount = 0;
            for (SysDiffTable SysDiffTable : tableInfos) {
                List<SysDiffColumn> columnInfos = synchronizer.getColumns(database, SysDiffTable.getTableName());
                columnInfos.forEach(SysDiffColumn -> {
                    SysDiffColumn.setSysDiffDatasourceId(datasourceId);
                    SysDiffColumn.setSysDiffSyncId(syncId);
                    SysDiffColumn.setSysDiffTableId(SysDiffTable.getSysDiffTableId());
                });
                sysDiffColumnService.saveBatch(columnInfos);
                columnCount += columnInfos.size();
            }

            updateDatasource(datasourceId, syncId, tableInfos.size());

            log.info("Datasource sync success, {} tables, {} columns", tableInfos.size(), columnCount);

        } finally {
            try {
                if (synchronizer != null) {
                    synchronizer.close();
                }
            } catch (Exception e) {
                log.error("Resource close fail", e);
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public void test(String type, String url, String username, String password) {
        DatasourceType datasourceType = DatasourceType.of(type);
        DatasourceSynchronizer synchronizer = null;
        try {
            switch (datasourceType) {
                case MYSQL:
                    synchronizer = new MysqlDatasourceSynchronizer(url, username, password);
                    break;
                case H2:
                    synchronizer = new H2DatasourceSynchronizer(url, username, password);
                    break;
                case PGSQL:
                    synchronizer = new PgsqlDatasourceSynchronizer(url, username, password);
                    break;
                case ORACLE:
                    synchronizer = new OracleDatasourceSynchronizer(url, username, password);
                    break;
                case TIDB:
                default:
                    throw new IllegalArgumentException("暂不支持: " + datasourceType);
            }
        } finally {
            try {
                if (synchronizer != null) {
                    synchronizer.close();
                }
            } catch (Exception e) {
                log.error("Resource close fail", e);
                throw new RuntimeException(e);
            }
        }
    }

    private void setConnectionAttr(SysDiffDatasource datasource) {
        DatasourceType datasourceType = DatasourceType.of(datasource.getType());
        String database = datasource.getDatabaseName();
        DatasourceConnectionAttr connectionAttr = null;
        switch (datasourceType) {
            case MYSQL:
                connectionAttr = DatasourceConnectionAttr.builder().catalog(Optional.ofNullable(datasource.getCatalog()).orElse("def")).schema(Optional.ofNullable(datasource.getSchema()).orElse(database)).build();
                break;
            case H2:
                connectionAttr = DatasourceConnectionAttr.builder().catalog(Optional.ofNullable(datasource.getCatalog()).orElse(database)).schema(Optional.ofNullable(datasource.getSchema()).orElse("'PUBLIC'")).build();
                break;
            case PGSQL:
                connectionAttr = DatasourceConnectionAttr.builder().catalog(Optional.ofNullable(datasource.getCatalog()).orElse(database)).schema(Optional.ofNullable(datasource.getSchema()).orElse(database)).build();
                break;
            case ORACLE:
                connectionAttr = DatasourceConnectionAttr.builder()
                        //FIXME 待修改
                        .tablespace(Optional.ofNullable(datasource.getCatalog()).orElse(database)).build();
                break;
            default:
                connectionAttr = new DatasourceConnectionAttr();
        }
        DatasourceConnectHelper.setConnectionAttr(connectionAttr);
    }

    private void updateDatasource(Long datasourceId, Long syncId, Integer tableCount) {
        SysDiffDatasource sysDiffDatasource = new SysDiffDatasource();
        sysDiffDatasource.setSysDiffDatasourceId(datasourceId);
        sysDiffDatasource.setSysDiffSyncId(syncId);
        sysDiffDatasource.setTableCount(tableCount);
        sysDiffDatasourceService.updateById(sysDiffDatasource);
    }

}
